package org.lc.kcjxzj.textcheck;

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.stereotype.Component;

/**
 * 基于Levenshtein距离的相似度计算器
 * LevenshteinDistance类中不同操作成本设置如下：

替换操作成本：
相似字符（如中英文标点）：0.2
中文↔中文：1.0
非中文↔非中文：0.8
中文↔非中文：1.2


删除操作成本：
空格：0.1
中文字符：1.0
其他字符：0.8

插入操作成本：
空格：0.1
中文字符：1.0
其他字符：0.8
 */

@Component
public class LevenshteinDistance implements SimilarityCalculator {
    
    private static final Map<Character, Character> PUNCTUATION_MAP = new HashMap<>();
    
    static {
        // 初始化标点符号映射
        PUNCTUATION_MAP.put('\u3002', '.');  // 。
        PUNCTUATION_MAP.put('\uff0c', ',');  // ，
        PUNCTUATION_MAP.put('\uff1b', ';');  // ；
        PUNCTUATION_MAP.put('\uff1a', ':');  // ：
        PUNCTUATION_MAP.put('\uff01', '!');  // ！
        PUNCTUATION_MAP.put('\uff1f', '?');  // ？
        PUNCTUATION_MAP.put('\uff08', '(');  // （
        PUNCTUATION_MAP.put('\uff09', ')');  // ）
        PUNCTUATION_MAP.put('\u3010', '[');  // 【
        PUNCTUATION_MAP.put('\u3011', ']');  // 】
        PUNCTUATION_MAP.put('\u201c', '"');  // "
        PUNCTUATION_MAP.put('\u201d', '"');  // "
        PUNCTUATION_MAP.put('\u2018', '\''); // '
        PUNCTUATION_MAP.put('\u2019', '\''); // '
    }

    @Override
    public double calculate(String text1, String text2) {
        if (text1 == null || text2 == null) {
            return 0.0;
        }

        // 处理空字符串的特殊情况
        if (text1.isEmpty() && text2.isEmpty()) {
            return 1.0;
        }
        if (text1.isEmpty() || text2.isEmpty()) {
            return 0.0;
        }

        // 预处理文本
        text1 = normalizeText(text1);
        text2 = normalizeText(text2);

        int len1 = text1.length();
        int len2 = text2.length();

        // 如果字符串完全相同
        if (text1.equals(text2)) {
            return 1.0;
        }

        // 计算长度比例因子，用于调整相似度
        double lengthRatio = (double) Math.min(len1, len2) / Math.max(len1, len2);

        // 使用滚动数组优化空间复杂度
        double[] prevRow = new double[len2 + 1];
        double[] currRow = new double[len2 + 1];

        // 初始化第一行
        for (int j = 0; j <= len2; j++) {
            prevRow[j] = j;
        }

        // 动态规划计算编辑距离
        for (int i = 1; i <= len1; i++) {
            char c1 = text1.charAt(i - 1);
            currRow[0] = i; // 初始化当前行第一个元素

            for (int j = 1; j <= len2; j++) {
                char c2 = text2.charAt(j - 1);
                
                if (c1 == c2 || isCharactersSimilar(c1, c2)) {
                    // 字符相同或相似，成本较低
                    currRow[j] = prevRow[j - 1] + (c1 == c2 ? 0 : 0.2);
                } else {
                    // 计算三种操作的成本
                    double replaceCost = getReplaceCost(c1, c2);
                    double deleteCost = getDeleteCost(c1);
                    double insertCost = getInsertCost(c2);
                    
                    currRow[j] = Math.min(
                        Math.min(
                            prevRow[j] + deleteCost,       // 删除
                            currRow[j - 1] + insertCost    // 插入
                        ),
                        prevRow[j - 1] + replaceCost       // 替换
                    );
                }
            }

            // 交换两行
            double[] temp = prevRow;
            prevRow = currRow;
            currRow = temp;
        }

        // 获取最终的编辑距离
        double editDistance = prevRow[len2];

        // 计算基础相似度
        double maxPossibleDistance = Math.max(len1, len2);
        double baseSimilarity = 1.0 - (editDistance / maxPossibleDistance);

        // 根据文本长度和特性调整相似度
        double adjustedSimilarity;
        if (Math.min(len1, len2) < 5) {
            // 短文本的相似度调整
            adjustedSimilarity = baseSimilarity * (0.7 + 0.3 * lengthRatio);
        } else if (allChinese(text1) && allChinese(text2)) {
            // 纯中文文本的相似度调整
            adjustedSimilarity = baseSimilarity * (0.9 + 0.1 * lengthRatio);
        } else {
            // 混合文本的相似度调整
            adjustedSimilarity = baseSimilarity * (0.8 + 0.2 * lengthRatio);
        }

        return Math.max(0.0, Math.min(1.0, adjustedSimilarity));
    }

    /**
     * 文本预处理
     */
    private String normalizeText(String text) {
        if (text == null) return "";
        
        // 将全角字符转换为半角字符
        text = text.chars()
                  .mapToObj(ch -> normalizeChar((char)ch))
                  .map(String::valueOf)
                  .collect(Collectors.joining());
        
        // 去除多余空白并统一空格
        return text.trim().replaceAll("\\s+", " ");
    }

    /**
     * 字符规范化
     */
    private char normalizeChar(char c) {
        // 检查标点符号映射
        Character normalized = PUNCTUATION_MAP.get(c);
        if (normalized != null) {
            return normalized;
        }
        
        // 全角转半角
        if (c >= 0xFF00 && c <= 0xFF5E) {
            return (char) (c - 0xFEE0);
        }
        
        return c;
    }

    /**
     * 判断两个字符是否相似
     */
    private boolean isCharactersSimilar(char c1, char c2) {
        if (c1 == c2) return true;
        
        // 检查标点符号映射
        Character norm1 = PUNCTUATION_MAP.get(c1);
        Character norm2 = PUNCTUATION_MAP.get(c2);
        
        if (norm1 != null && norm2 != null) {
            return norm1.equals(norm2);
        }
        if (norm1 != null) {
            return norm1 == c2;
        }
        if (norm2 != null) {
            return norm2 == c1;
        }
        
        return false;
    }

    /**
     * 获取字符替换操作的成本
     */
    private double getReplaceCost(char c1, char c2) {
        if (isCharactersSimilar(c1, c2)) return 0.2;
        if (isChinese(c1) && isChinese(c2)) return 1.0;
        if (!isChinese(c1) && !isChinese(c2)) return 0.8;
        return 1.2; // 中文和非中文字符间的替换成本最高
    }

    /**
     * 获取删除操作的成本
     */
    private double getDeleteCost(char c) {
        if (Character.isWhitespace(c)) return 0.1;
        if (isChinese(c)) return 1.0;
        return 0.8;
    }

    /**
     * 获取插入操作的成本
     */
    private double getInsertCost(char c) {
        if (Character.isWhitespace(c)) return 0.1;
        if (isChinese(c)) return 1.0;
        return 0.8;
    }

    /**
     * 判断字符是否为中文
     */
    private boolean isChinese(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        return ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
            || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
            || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
            || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C
            || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D
            || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
            || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT
            || (c >= 0x3400 && c <= 0x4DBF)   // CJK扩展A
            || (c >= 0x20000 && c <= 0x2A6DF) // CJK扩展B
            || (c >= 0x2A700 && c <= 0x2B73F) // CJK扩展C
            || (c >= 0x2B740 && c <= 0x2B81F) // CJK扩展D
            || (c >= 0xF900 && c <= 0xFAFF)   // CJK兼容汉字
            || (c >= 0x2F800 && c <= 0x2FA1F); // CJK兼容扩展
    }

    /**
     * 判断文本是否全为中文
     */
    private boolean allChinese(String text) {
        for (char c : text.toCharArray()) {
            if (!isChinese(c) && !Character.isWhitespace(c)) {
                return false;
            }
        }
        return true;
    }
}